/*
 *------------------------------------------------------------------------------
 * @File      :    sc4210_mipi.c
 * @Date      :    2021-3-20
 * @Author    :    lomboswer <lomboswer@lombotech.com>
 * @Brief     :    Source file for MDP(Media Development Platform).
 *
 * Copyright (C) 2020-2021, LomboTech Co.Ltd. All rights reserved.
 *------------------------------------------------------------------------------
 */
#include "ei_comm_camera.h"
#include "camera_usr.h"

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */

#define SNS_ID 4210
#define SNS_NAME  "sc4210_mipi"
#define DEV_TYPE MCSI
static VISS_DEV gaVissDev[ISP_MAX_DEV_NUM] = {-1};
static SNS_STATE_S g_sastSns[VISS_MAX_DEV_NUM];

#define MAX_SENSOR_GAIN         (256)
#define MAX_SHORT_EXP           (180)

/* cleaned_0x03_SC4210_MIPI_27Minput_4lane_405Mbps_12bit_30fps_2560x1440_non-continue */
static const SNS_REG_S s_aRaw1440p4lane30fps12bit[] = {
    {0x0103,0x01},
    {0x0100,0x00},
    {0x36e9,0x80},
    {0x36f9,0x80},
    {0x3001,0x07},
    {0x3002,0xc0},
    {0x300a,0x2c},
    {0x300f,0x00},
    {0x3018,0x73},
    {0x301f,0x03},
    {0x3031,0x0c},
    {0x3038,0x22},
    {0x320c,0x05},
    {0x320d,0x46},
    {0x3220,0x10},
    {0x3225,0x01},
    {0x3227,0x03},
    {0x3229,0x08},
    {0x3231,0x01},
    {0x3241,0x02},
    {0x3243,0x03},
    {0x3249,0x17},
    {0x3251,0x08},
    {0x3253,0x08},
    {0x325e,0x00},
    {0x325f,0x00},
    {0x3273,0x01},
    {0x3301,0x28},
    {0x3302,0x18},
    {0x3304,0x20},
    {0x3305,0x00},
    {0x3306,0x74},
    {0x3000,0x00},
    {0x3308,0x10},
    {0x3309,0x40},
    {0x330a,0x00},
    {0x330b,0xe8},
    {0x330e,0x18},
    {0x3312,0x02},
    {0x3314,0x84},
    {0x331e,0x19},
    {0x331f,0x39},
    {0x3320,0x05},
    {0x3338,0x10},
    {0x334c,0x10},
    {0x335d,0x20},
    {0x3366,0x92},
    {0x3367,0x08},
    {0x3368,0x05},
    {0x3369,0xdc},
    {0x336a,0x0b},
    {0x336b,0xb8},
    {0x336c,0xc2},
    {0x337a,0x08},
    {0x337b,0x10},
    {0x337e,0x40},
    {0x33a3,0x0c},
    {0x33e0,0xa0},
    {0x33e1,0x08},
    {0x33e2,0x00},
    {0x33e3,0x10},
    {0x33e4,0x10},
    {0x33e5,0x00},
    {0x33e6,0x10},
    {0x33e7,0x10},
    {0x33e8,0x00},
    {0x33e9,0x10},
    {0x33ea,0x16},
    {0x33eb,0x00},
    {0x33ec,0x10},
    {0x33ed,0x18},
    {0x33ee,0xa0},
    {0x33ef,0x08},
    {0x33f4,0x00},
    {0x33f5,0x10},
    {0x33f6,0x10},
    {0x33f7,0x00},
    {0x33f8,0x10},
    {0x33f9,0x10},
    {0x33fa,0x00},
    {0x33fb,0x10},
    {0x33fc,0x16},
    {0x33fd,0x00},
    {0x33fe,0x10},
    {0x33ff,0x18},
    {0x360f,0x05},
    {0x3622,0xff},
    {0x3624,0x07},
    {0x3625,0x02},
    {0x3630,0xc4},
    {0x3631,0x80},
    {0x3632,0x88},
    {0x3633,0x22},
    {0x3634,0x64},
    {0x3635,0x20},
    {0x3636,0x20},
    {0x3638,0x28},
    {0x363b,0x03},
    {0x363c,0x06},
    {0x363d,0x06},
    {0x366e,0x04},
    {0x3670,0x48},
    {0x3671,0xff},
    {0x3672,0x1f},
    {0x3673,0x1f},
    {0x367a,0x40},
    {0x367b,0x40},
    {0x3690,0x42},
    {0x3691,0x44},
    {0x3692,0x44},
    {0x3699,0x80},
    {0x369a,0x9f},
    {0x369b,0x9f},
    {0x369c,0x40},
    {0x369d,0x40},
    {0x36a2,0x40},
    {0x36a3,0x40},
    {0x36cc,0x2c},
    {0x36cd,0x30},
    {0x36ce,0x30},
    {0x36d0,0x20},
    {0x36d1,0x40},
    {0x36d2,0x40},
    {0x36ea,0x36},
    {0x36eb,0x16},
    {0x36ec,0x03},
    {0x36ed,0x0c},
    {0x36fa,0x37},
    {0x36fb,0x14},
    {0x36fc,0x00},
    {0x36fd,0x2c},
    {0x3817,0x20},
    {0x3905,0xd8},
    {0x3908,0x11},
    {0x391b,0x80},
    {0x391c,0x0f},
    {0x391d,0x01},
    {0x3933,0x24},
    {0x3934,0xb0},
    {0x3935,0x80},
    {0x3936,0x1f},
    {0x3940,0x68},
    {0x3942,0x04},
    {0x3943,0xc0},
    {0x3980,0x00},
    {0x3981,0x50},
    {0x3982,0x00},
    {0x3983,0x40},
    {0x3984,0x00},
    {0x3985,0x20},
    {0x3986,0x00},
    {0x3987,0x10},
    {0x3988,0x00},
    {0x3989,0x20},
    {0x398a,0x00},
    {0x398b,0x30},
    {0x398c,0x00},
    {0x398d,0x50},
    {0x398e,0x00},
    {0x398f,0x60},
    {0x3990,0x00},
    {0x3991,0x70},
    {0x3992,0x00},
    {0x3993,0x36},
    {0x3994,0x00},
    {0x3995,0x20},
    {0x3996,0x00},
    {0x3997,0x14},
    {0x3998,0x00},
    {0x3999,0x20},
    {0x399a,0x00},
    {0x399b,0x50},
    {0x399c,0x00},
    {0x399d,0x90},
    {0x399e,0x00},
    {0x399f,0xf0},
    {0x39a0,0x08},
    {0x39a1,0x10},
    {0x39a2,0x20},
    {0x39a3,0x40},
    {0x39a4,0x20},
    {0x39a5,0x10},
    {0x39a6,0x08},
    {0x39a7,0x04},
    {0x39a8,0x18},
    {0x39a9,0x30},
    {0x39aa,0x40},
    {0x39ab,0x60},
    {0x39ac,0x38},
    {0x39ad,0x20},
    {0x39ae,0x10},
    {0x39af,0x08},
    {0x39b9,0x00},
    {0x39ba,0xa0},
    {0x39bb,0x80},
    {0x39bc,0x00},
    {0x39bd,0x44},
    {0x39be,0x00},
    {0x39bf,0x00},
    {0x39c0,0x00},
    {0x39c5,0x41},
    {0x3e00,0x00},
    {0x3e01,0xbb},
    {0x3e02,0x40},
    {0x3e03,0x0b},
    {0x3e06,0x00},
    {0x3e07,0x80},
    {0x3e08,0x03},
    {0x3e09,0x40},
    {0x3e0e,0x6a},
    {0x3e26,0x40},
    {0x4407,0xb0},
    {0x4418,0x0b},
    {0x4501,0xb4},
    {0x4509,0x10},
    {0x4603,0x00},
    {0x4800,0x24},
    {0x4837,0x28},
    {0x5000,0x0e},
    {0x550f,0x20},
    {0x5784,0x10},
    {0x5785,0x08},
    {0x5787,0x06},
    {0x5788,0x06},
    {0x5789,0x00},
    {0x578a,0x06},
    {0x578b,0x06},
    {0x578c,0x00},
    {0x5790,0x10},
    {0x5791,0x10},
    {0x5792,0x00},
    {0x5793,0x10},
    {0x5794,0x10},
    {0x5795,0x00},
    {0x57c4,0x10},
    {0x57c5,0x08},
    {0x57c7,0x06},
    {0x57c8,0x06},
    {0x57c9,0x00},
    {0x57ca,0x06},
    {0x57cb,0x06},
    {0x57cc,0x00},
    {0x57d0,0x10},
    {0x57d1,0x10},
    {0x57d2,0x00},
    {0x57d3,0x10},
    {0x57d4,0x10},
    {0x57d5,0x00},
    {0x36e9,0x27},
    {0x36f9,0x20},
};

/*SC4210_MIPI_10bit_4lane_626.4Mbps_60fps_2560x1440_VC_BSI_NEW*/
static const SNS_REG_S s_aRaw1440p4lane2f30fps10bit[] = {
    {0x0103,0x01},
    {0x0100,0x00},
    {0x36e9,0xa4},//pll1 bypass
    {0x36f9,0xa0},//pll2 bypass

    //timing
    {0x335d,0x00}, //[6]sp rst all1  1008
    {0x3312,0x02}, //[7]sp dcg all1
    {0x336c,0xc2}, //hcg rst all1 c2
    {0x337e,0x40},
    {0x3338,0x10},  //[4] sp addr to rp addr disable

    //1008
    {0x335d,0x40},
    {0x3312,0x82},
    {0x3309,0x68},
    {0x331f,0x59},
    {0x3306,0x58},
    {0x3302,0x18},
    {0x3301,0x30},
    {0x3320,0x01},
    {0x3633,0x33},
    {0x3634,0x64},
    {0x3624,0x07}, //cnt_clk delay

    //fullwell
    {0x4418,0x3a}, //11.9K fullwell

    //blksun
    {0x3622,0xff},
    {0x3630,0xc4},
    {0x3631,0x80},

    //pump
    {0x3635,0x42},
    {0x363b,0x08},
    {0x363c,0x06},
    {0x363d,0x06},
    {0x3038,0x22},

    //power save mode
    {0x3253,0x08}, //quit power save mode in ahead of 8 half row of vts
    {0x325e,0x00}, //exp threshold
    {0x325f,0x00},
    {0x3251,0x08}, //[6]: 0: vts  1:exp

    //12bit
    {0x4418,0x0e},
    {0x330a,0x02},
    {0x330b,0xf8},  //0601
    {0x3305,0x01},
    {0x3306,0x60},  //0601
    {0x320c,0x0a},
    {0x320d,0x8c},
    {0x4501,0xc4},  //

    ///////digital updates start////////////
    // 05-23-2018

    {0x33e0,0xa0},//20181010
    {0x33e1,0x08},
    {0x33e2,0x02},
    {0x33e3,0x10},
    {0x33e4,0x20},
    {0x33e5,0x00},
    {0x33e6,0x06},
    {0x33e7,0x10},
    {0x33e8,0x00},
    {0x33e9,0x02},
    {0x33ea,0x20},
    {0x33eb,0x00},
    {0x33ec,0x04},
    {0x33ed,0x10},

    //05-23-2018
    {0x3225,0x01},
    {0x3227,0x03},

    //blc, 05-23-2018
    {0x391b,0x80},
    {0x391c,0x0f},
    {0x3935,0x80},
    {0x3936,0x1f},
    {0x3908,0x11},

    //dummy addr & blc addr
    {0x3273,0x01},
    {0x3241,0x02},
    {0x3243,0x03},
    {0x3249,0x17},
    {0x3229,0x08},
    {0x3905,0xd8},//20181010 one channel blc

    //0x336d,0x01, //cmp timing
    //0x337f,0x2d,
    //0x331c,0x04,

    ///////digital updates end////////////
    //DVP mode : close mipi
    //0x3018,0x6f,
    //0x3019,0xff,
    //0x301c,0xb4,
    //0x300f,0xff,
    //0x3001,0xff,
    //0x3000,0x0f,
    //0x300f,0x00,
    //0x3002,0xff,
    //0x300a,0x2c,
    //0x301c,0x94,
    //0x3018,0x2f,
    //0x301a,0xf8,
    //0x3c00,0x45,
    //0x3030,0x02,
    //0x303f,0x81,

    //mipi
    {0x3018,0x73},//[7:5] lane_num-1 [4] digital mipi pad en 1:mipi 0:DVP
    {0x3031,0x0a},//[3:0] bitmode
    {0x300f,0xff},
    {0x3001,0x07},//dvp_dat_oen[7:0]
    {0x3000,0x00},//{dvp_dat_i[2:1],dvp_dat_oen[13:8]
    {0x300f,0x00},
    {0x3002,0xc0},//[6] oen href [5] oen pclk  not reused href  0705
    {0x300a,0x2c},//{d_efsync_i,d_efsync_oen,r_efsync_sel,r_io_efsync,d_fsync_i,d_fsync_oen,r_fsync_sel,r_io_fsync}

    {0x4603,0x00},//[0] data_fifo mipi mode
    {0x4837,0x1a},//[7:0] pclk period * 2  1009


    {0x36ea,0x3a}, //729Mbps->405Mbps
    //mipi end

    //exp&gain
    {0x3e01,0xba},
    {0x3e02,0xe0},
    {0x3e08,0x03},
    {0x3e09,0x20},
    {0x3e06,0x00},

    //0613
    {0x4418,0x0d},
    {0x3638,0x27},

    //0614
    {0x3635,0x40},
    {0x363b,0x06},

    //logic
    {0x3622,0xff},
    {0x3633,0x22},

    //internal logic_20180706
    //0x366e,0x04,
    //0x360f,0x05,  //0x3622 logic enable
    //0x367a,0x08,  //<2x gain
    //0x367b,0x08,  //>=2x gain
    //0x3671,0xff,   //0x3622 logic value
    //0x3672,0x5f,
    //0x3673,0x5f,  //0x3680 read 0x3622 value
    //
    //0x3670,0x08, //0x3633 logic enable
    //0x369c,0x08,  //<2x gain
    //0x369d,0x08,  //>=2x gain
    //0x3690,0x22,  //0x3633 logic value
    //0x3691,0x66,
    //0x3692,0x66,  //0x3683 read 0x3633 value

    //621Mbps_20180802
    {0x36e9,0xa4},
    {0x36ea,0x29},
    {0x4837,0x1a},

    //high temp_20180805
    {0x39a0,0x14},  //0x08,
    {0x39a1,0x28},  //0x10,
    {0x39a2,0x48},  //0x20,
    {0x39a3,0x70},  //0x40,
    {0x39a4,0x10},  //0x20,
    {0x39a5,0x10},
    {0x39a6,0x08},
    {0x39a7,0x04},
    {0x39a8,0x10},  //0x18,
    {0x39a9,0x28},  //0x30,
    {0x39aa,0x40},
    {0x39ab,0x68},  //0x60,
    {0x39ac,0x30},  //0x38,
    {0x39ad,0x20},
    {0x39ae,0x10},
    {0x39af,0x08},
    {0x3980,0x00},
    {0x3981,0x30},
    {0x3982,0x00},
    {0x3983,0x18},
    {0x3984,0x00},
    {0x3985,0x14},
    {0x3986,0x00},
    {0x3987,0x08},
    {0x3988,0x00},
    {0x3989,0x18},
    {0x398a,0x00},
    {0x398b,0x28},
    {0x398c,0x00},
    {0x398d,0x38},
    {0x398e,0x00},
    {0x398f,0x48},
    {0x3990,0x00},
    {0x3991,0x50},
    {0x3992,0x00},
    {0x3993,0x28},
    {0x3994,0x00},
    {0x3995,0x18},
    {0x3996,0x00},
    {0x3997,0x0c},
    {0x3998,0x00},
    {0x3999,0x18},
    {0x399a,0x00},
    {0x399b,0x30},
    {0x399c,0x00},
    {0x399d,0x50},
    {0x399e,0x00},
    {0x399f,0x80},
    {0x39b9,0x00},
    {0x39ba,0x66},
    {0x39bb,0x00},
    {0x39bc,0x00},
    {0x39bd,0x4b},
    {0x39be,0xc0},
    {0x39bf,0x00},
    {0x39c0,0x00},
    {0x3933,0x28},
    {0x3934,0xc0},
    {0x3940,0x60},
    {0x3942,0x08},
    {0x3943,0xd0},
    {0x39c5,0x41},

    {0x3817,0x20},//grp hold delay
    {0x3314,0x14},

    //0928
    //60fps   121.5M sysclk  607.5M cntclk  621Mbps x 4
    {0x36e9,0xa4},
    {0x36ea,0x29},
    {0x36eb,0x06},
    {0x36ec,0x03},
    {0x36ed,0x04},
    {0x36f9,0xa0},
    {0x36fa,0x37},
    {0x36fb,0x04},
    {0x36fc,0x00},
    {0x36fd,0x24},
    {0x320c,0x05},
    {0x320d,0x46},
    {0x4501,0xa4},
    {0x4418,0x1a},
    {0x3638,0x2a},
    {0x3304,0x20},
    {0x331e,0x19},
    {0x3309,0x50},
    {0x331f,0x49},
    {0x3305,0x00},
    {0x3306,0x78}, //[68,--]
    {0x330a,0x00},
    {0x330b,0xd8}, //[c8,d8]
    {0x3301,0x26}, //[18,--]
    {0x3320,0x05},
    {0x337a,0x08}, //count_keep/up
    {0x337b,0x10},
    {0x33a3,0x0c},
    {0x3308,0x10},
    {0x3366,0x92},
    {0x4509,0x10},

    //preprecharge
    {0x3314,0x84},
    {0x330e,0x20}, //[f,2e]
    {0x334c,0x10},

    //1008
    {0x3636,0x28},
    {0x4418,0x1a},

    //timing
    {0x335d,0x00}, //[6]sp rst all1  1008
    {0x3312,0x02}, //[7]sp dcg all1
    {0x336c,0xc2}, //hcg rst all1 c2
    {0x337e,0x40},
    {0x3338,0x10},  //[4] sp addr to rp addr disable

    //1008
    //0x335d,0x40,//hvdd cap must be 4.7u   20181107
    //0x3312,0x82,

    //1010      }
    {0x4418,0x18},
    {0x3905,0xd8},//20181010 one channel blc
    //0x3625,0x0}2,//20181010 sensor default

    //logic 20181010
    {0x3622,0xff},
    {0x3633,0x42},

    //internal logic_20181010
    //0x366e,0x04,
    //0x360f,0x05,  //0x3622 logic enable
    //0x367a,0x08,  //<2x gain
    //0x367b,0x08,  //>=2x gain
    //0x3671,0xff,   //0x3622 logic value
    //0x3672,0x9f,
    //0x3673,0x9f,  //0x3680 read 0x3622 value
    //
    //0x3670,0x48, //0x3670[3]:0x3633 logic enable ---- 0x3670[6]:0x363a logic enable
    //0x369c,0x08,  //<2x gain
    //0x369d,0x08,  //>=2x gain
    //0x3690,0x42,  //0x3633 logic value
    //0x3691,0x66,
    //0x3692,0x66,  //0x3683 read 0x3633 value
    //
    //0x36a2,0x08,  //<2x gain  0x363a logic, current value read out from 0x3686
    //0x36a3,0x08,  //>=2x gain
    //0x3699,0x80,
    //0x369a,0x9f,
    //0x369b,0x9f,

    //VC 20180705
    {0x3220,0x53},
    {0x320e,0x0b},
    {0x320f,0xb8},
    {0x3250,0x3f},
    {0x4816,0x11},

    //20181030

    {0x3231,0x01},
    {0x3220,0x50},
    {0x3e0e,0x6a},
    //modify fine gain map to 40~7f
    {0x3625,0x02},
    {0x3636,0x20},
    {0x4418,0x18},
    //modify mipi clk = 626.4M
    {0x36e9,0xb4},
    {0x36ea,0x23},
    {0x4819,0x40},
    {0x4829,0x01},
    {0x4837,0x1a},

    //internal logic_20181030
    {0x366e,0x04},
    {0x360f,0x05},  //0x360f[0]: 0x3622 logic enable
    {0x367a,0x40},  //<1*dcg gain
    {0x367b,0x48},  //>=2*dcg gain
    {0x3671,0xff},   //0x3622 logic value
    {0x3672,0x9f},
    {0x3673,0x9f},  //0x3680 read 0x3622 value
    {0x3670,0x48}, //0x3670[3]:0x3633 logic enable ---- 0x3670[6]:0x363a logic enable
    {0x369c,0x40},  //<1*dcg gain
    {0x369d,0x48},  //>=2*dcg gain
    {0x3690,0x43},  //0x3633 logic value
    {0x3691,0x54},
    {0x3692,0x66},  //0x3683 read 0x3633 value
    {0x36a2,0x40},  //<1*dcg gain 0x363a logic, current value read out from 0x3686
    {0x36a3,0x48},  //>=2*dcg gain
    {0x3699,0x8c},
    {0x369a,0x96},
    {0x369b,0x9f},
    {0x36d0,0x20},//0x36d0[5]=1: 0x363e pwce auto en ,  0x36cf auto pwce(FPN, horizontal lines/fullwell)
    {0x36d1,0x40},//gain 0
    {0x36d2,0x40},//gain 1
    {0x36cc,0x2c},//sel 0
    {0x36cd,0x30},//sel 1
    {0x36ce,0x30},//sel 2
    {0x3364,0x1e},//bit[4] comprst auto enable  bit[3] 0~gain 10~1f 1~ gain 20~3f  //0x33f2 readout
    {0x3301,0x24},//comprst sel0 when dcg off
    {0x3393,0x24}, //comprst sel1 when dcg off
    {0x3394,0x24}, //comprst sel2 when dcg off
    {0x3395,0x24}, //comprst sel3 when dcg off
    {0x3390,0x08}, //comprst gain0 when dcg off
    {0x3391,0x08}, //comprst gain1 when dcg off
    {0x3392,0x08}, //comprst gain2 when dcg off
    {0x3399,0x1c},//comprst sel0 when dcg on
    {0x339a,0x26}, //comprst sel1 when dcg on
    {0x339b,0x1d}, //comprst sel2 when dcg on
    {0x339c,0x26}, //comprst sel3 when dcg on
    {0x3396,0x08}, //comprst gain0 when dcg on
    {0x3397,0x38}, //comprst gain1 when dcg on
    {0x3398,0x3c}, //comprst gain2 when dcg on[40,4f]=1d,[50,5f]=26,[60,6f]=1d,[70,7f]=26

    //dpc 201810}30
    {0x33e0,0xa0},
    {0x33e1,0x08},
    {0x33e2,0x02},
    {0x33e3,0x06},
    {0x33e4,0x07},
    {0x33e5,0x02},
    {0x33e6,0x04},
    {0x33e7,0x08},
    {0x33e8,0x00},
    {0x33e9,0x06},
    {0x33ea,0x10},
    {0x33eb,0x00},
    {0x33ec,0x04},
    {0x33ed,0x10},
    {0x33ee,0xa0},
    {0x33ef,0x08},
    {0x33f4,0x02},
    {0x33f5,0x06},
    {0x33f6,0x07},
    {0x33f7,0x02},
    {0x33f8,0x04},
    {0x33f9,0x08},
    {0x33fa,0x00},
    {0x33fb,0x06},
    {0x33fc,0x10},
    {0x33fd,0x00},
    {0x33fe,0x04},
    {0x33ff,0x10},
    {0x5784,0x0b},
    {0x5787,0x07},
    {0x5788,0x06},
    {0x5789,0x02},
    {0x578a,0x08},
    {0x578b,0x04},
    {0x578c,0x02},
    {0x57c4,0x0b},
    {0x57c7,0x07},
    {0x57c8,0x06},
    {0x57c9,0x02},
    {0x57ca,0x08},
    {0x57cb,0x04},
    {0x57cc,0x02},
    {0x5000,0x06},

    //20181106
    {0x3e26,0x40},//time point of blc dithering

    //20181115
    {0x4418,0x16},//fullwell
    {0x3638,0x28},//black sun, tempN
    {0x3306,0x78},//[hl,bs][1,6a,7a]      [2,68,7a]   [3,6a,7a]   0x330b=0xe0
    //0x3304,0x20,//[te,to][1,1c,28]    [2,1a,28]   [3,1c,28]
    //0x3309,0x50,//[te,to][1,4c,58]    [2,4a,58]   [3,4c,58]
    {0x330b,0xe0},//[bs,to][1,d6,ea]      [2,d6,ea]   [3,d6,ea]   0x3306=0x78
    //0x330e,0x20,//[1,4,2e]

    //vco=27/2*5*9=607.5
    //sysclk=vco/5=121.5
    //countclk=vco/1=607.5
    //countclk:sysclk=5:1

    //20181126
    {0x5784,0x10},
    {0x5785,0x08},
    {0x5787,0x06},
    {0x5788,0x06},
    {0x5789,0x00},
    {0x578a,0x06},
    {0x578b,0x06},
    {0x578c,0x00},
    {0x5790,0x10},
    {0x5791,0x10},
    {0x5792,0x00},
    {0x5793,0x10},
    {0x5794,0x10},
    {0x5795,0x00},
    {0x57c4,0x10},
    {0x57c5,0x08},
    {0x57c7,0x06},
    {0x57c8,0x06},
    {0x57c9,0x00},
    {0x57ca,0x06},
    {0x57cb,0x06},
    {0x57cc,0x00},
    {0x57d0,0x10},
    {0x57d1,0x10},
    {0x57d2,0x00},
    {0x57d3,0x10},
    {0x57d4,0x10},
    {0x57d5,0x00},
    {0x33e0,0xa0},
    {0x33e1,0x08},
    {0x33e2,0x00},
    {0x33e3,0x10},
    {0x33e4,0x10},
    {0x33e5,0x00},
    {0x33e6,0x10},
    {0x33e7,0x10},
    {0x33e8,0x00},
    {0x33e9,0x10},
    {0x33ea,0x16},
    {0x33eb,0x00},
    {0x33ec,0x10},
    {0x33ed,0x18},
    {0x33ee,0xa0},
    {0x33ef,0x08},
    {0x33f4,0x00},
    {0x33f5,0x10},
    {0x33f6,0x10},
    {0x33f7,0x00},
    {0x33f8,0x10},
    {0x33f9,0x10},
    {0x33fa,0x00},
    {0x33fb,0x10},
    {0x33fc,0x16},
    {0x33fd,0x00},
    {0x33fe,0x10},
    {0x33ff,0x18},

    //20181207
    {0x3905,0x98},//4 channel blc
    {0x4509,0x08},//init code
    {0x36ed,0x0c},//local bias en, pwdn current
    {0x36fd,0x2c},

    //20181210 high temperature
    {0x3933,0x1f},//m
    {0x3934,0xff},
    {0x3942,0x04},
    {0x393e,0x01},
    {0x39bc,0x00},//LeftK
    {0x39bd,0x58},
    {0x39be,0xc0},
    {0x39a0,0x14},
    {0x39a1,0x28},
    {0x39a2,0x48},
    {0x39a3,0x70},
    {0x39a4,0x18},//posH
    {0x39a5,0x10},
    {0x39a5,0x08},
    {0x39a5,0x04},
    {0x3980,0x00},//KH
    {0x3981,0x30},
    {0x3982,0x00},
    {0x3983,0x2c},
    {0x3984,0x00},
    {0x3985,0x15},
    {0x3986,0x00},
    {0x3987,0x10},
    {0x3988,0x00},
    {0x3989,0x30},
    {0x398a,0x00},
    {0x398b,0x28},
    {0x398c,0x00},
    {0x398d,0x30},
    {0x398e,0x00},
    {0x398f,0x70},
    {0x39b9,0x00},//TopV
    {0x39ba,0x00},
    {0x39bb,0x00},
    {0x39a8,0x01},//POSV
    {0x39a9,0x14},
    {0x39aa,0x30},
    {0x39ab,0x50},
    {0x39ac,0x40},
    {0x39ad,0x20},
    {0x39ae,0x10},
    {0x39af,0x08},
    {0x3990,0x05},//KV
    {0x3991,0x00},
    {0x3992,0x00},
    {0x3993,0x60},
    {0x3994,0x00},
    {0x3995,0x30},
    {0x3996,0x00},
    {0x3997,0x10},
    {0x3998,0x00},
    {0x3999,0x1c},
    {0x399a,0x00},
    {0x399b,0x48},
    {0x399c,0x00},
    {0x399d,0x90},
    {0x399e,0x00},
    {0x399f,0xc0},
    {0x3990,0x0a},//KV
    {0x39aa,0x28},//PosV
    {0x39ac,0x30},//PosV

    //20181212
    {0x363b,0x03},//vrefh 3.0v
    {0x3635,0x20},//txvdd 2.8v

    //20181213 auto precharge
    {0x335d,0x20},
    {0x330e,0x20}, //[f,2e]
    {0x3367,0x08},
    {0x3368,0x0b},//vts-{0x3e23,0x3e24}
    {0x3369,0x04},
    {0x336a,0x16},//(vts-{0x3e23,0x3e24})*2
    {0x336b,0x08},
    {0x3362,0x72},//short exp tx en
    {0x3360,0x20},//short exp tx width
    {0x4819,0x40},//hs_zero   hdr Compression timing
    {0x4829,0x01},//hs_exi
    //0x4825,0x32,//lpx
    {0x4837,0x1b},//[7:0] pclk period*2

    //20181215
    //0x3817,0x21,//group hold

    //20181217
    {0x550f,0x20},//otp dpc
    {0x4407,0xb0},

    //20181224
    {0x3253,0x10},//ramp local buffer margin

    //20190109
    //0x4837,0x19,//[7:0] pclk period*2

    //20190111
    {0x3632,0x88},//idac_bufs driver

    //20190117
    {0x391d,0x21},  //digital dithering always on

    //20190815
    {0x5000,0x0e},//otp dpc

    //init
    {0x3e00,0x01},//max long expsoure=0x15fe, max short expsoure=160  --> <16:1
    {0x3e01,0x5f},
    {0x3e02,0xe0},
    {0x3e03,0x0b},
    {0x3e04,0x16},//modefied by tbl default 0x16
    {0x3e05,0x00},
    {0x3e23,MAX_SHORT_EXP >> 8},
    {0x3e24,MAX_SHORT_EXP & 0xff},
    {0x3e06,0x00},
    {0x3e07,0x80},
    {0x3e08,0x03},
    {0x3e09,0x40},
    {0x3e10,0x00},
    {0x3e11,0x80},
    {0x3e12,0x06},//modefied by tbl default 0x03
    {0x3e13,0x40},
    {0x36e9,0x34},//pll1 enable
    {0x36f9,0x20},//pll2 enable
};

static CAMERA_POWER_ACT_S s_stPowerUpAct[] = {
    {SNS_RESET, SNS_DOWN},
    {SNS_DELAY, 5},
    {SNS_PWDN, SNS_DOWN},
    {SNS_DELAY, 20},
    {SNS_RESET, SNS_UP},
    {SNS_DELAY, 5},
    {SNS_PWDN, SNS_UP},
    {SNS_DELAY, 2},
};

static CAMERA_POWER_ACT_S s_sPowerDownAct[] = {
    {SNS_RESET, SNS_DOWN},
    {SNS_DELAY, 10},
    {SNS_PWDN, SNS_DOWN},
};

static SNS_TYPE_ATTR_S s_astSnsAttr[] = {
    {
        .enSnsType                  = SC4210_MIPI_2560_1440_25FPS_RAW12,
        .enPixelFormat              = PIX_FMT_RGB_BAYER_12BITS,
        .enRgbSeq                   = VISS_RGB_SEQ_BGGR,
        .stSize                     = {2560, 1440},
        .u32ModuleClk               = 198000000,
        .u32Mclock                  = 27000000,
        .enWorkMode                 = VISS_WORK_MODE_1Chn,

        .u32IspClk                  = 126000000,
        .u32IppuClk                 = 252000000,
        .u32Pclk                    = 121500000,
        .u32Vts                     = 1800,
        .u32Hts                     = 2700,
        .enIspWdrMode               = WDR_MODE_NONE,

        .u32FrameRate                = 25,
        .astRegCfgs[0].pstRegs      = s_aRaw1440p4lane30fps12bit,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aRaw1440p4lane30fps12bit),

        .stDevCfg.stMcsiCfg.u32PhyFreq  = 405000000,
        .stDevCfg.stMcsiCfg.enDlanes    = VISS_LANE_NUM_4Lane,
    },
    {
        .enSnsType                  = SC4210_MIPI_2560_1440_30FPS_RAW12,
        .enPixelFormat              = PIX_FMT_RGB_BAYER_12BITS,
        .enRgbSeq                   = VISS_RGB_SEQ_BGGR,
        .stSize                     = {2560, 1440},
        .u32ModuleClk               = 198000000,
        .u32Mclock                  = 27000000,
        .enWorkMode                 = VISS_WORK_MODE_1Chn,

        .u32IspClk                  = 126000000,
        .u32IppuClk                 = 252000000,
        .u32Pclk                    = 121500000,
        .u32Vts                     = 1500,
        .u32Hts                     = 2700,
        .enIspWdrMode               = WDR_MODE_NONE,

        .u32FrameRate                = 30,
        .astRegCfgs[0].pstRegs      = s_aRaw1440p4lane30fps12bit,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aRaw1440p4lane30fps12bit),

        .stDevCfg.stMcsiCfg.u32PhyFreq  = 405000000,
        .stDevCfg.stMcsiCfg.enDlanes    = VISS_LANE_NUM_4Lane,
    },
    {
        .enSnsType                  = SC4210_MIPI_2560_1440_2TO1_25FPS_RAW10,
        .enPixelFormat              = PIX_FMT_RGB_BAYER_10BITS,
        .enRgbSeq                   = VISS_RGB_SEQ_BGGR,
        .stSize                     = {2560, 1440},
        .u32ModuleClk               = 297000000,
        .u32Mclock                  = 27000000,
        .enWorkMode                 = VISS_WORK_MODE_2Chn,
        .enWdrMode                  = VISS_WDR_MODE_VC,

        .u32IspClk                  = 126000000,
        .u32IppuClk                 = 252000000,
        .u32Pclk                    = 243000000,
        .u32Vts                     = 3600,
        .u32Hts                     = 2700,
        .enIspWdrMode               = WDR_MODE_2TO1_FRAME,

        .u32FrameRate                = 25,
        .astRegCfgs[0].pstRegs      = s_aRaw1440p4lane2f30fps10bit,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aRaw1440p4lane2f30fps10bit),

        .stDevCfg.stMcsiCfg.u32PhyFreq  = 729000000,
        .stDevCfg.stMcsiCfg.enDlanes    = VISS_LANE_NUM_4Lane,
    },
    {
        .enSnsType                  = SC4210_MIPI_2560_1440_2TO1_30FPS_RAW10,
        .enPixelFormat              = PIX_FMT_RGB_BAYER_10BITS,
        .enRgbSeq                   = VISS_RGB_SEQ_BGGR,
        .stSize                     = {2560, 1440},
        .u32ModuleClk               = 297000000,
        .u32Mclock                  = 27000000,
        .enWorkMode                 = VISS_WORK_MODE_2Chn,
        .enWdrMode                  = VISS_WDR_MODE_VC,

        .u32IspClk                  = 126000000,
        .u32IppuClk                 = 252000000,
        .u32Pclk                    = 243000000,
        .u32Vts                     = 3000,
        .u32Hts                     = 2700,
        .enIspWdrMode               = WDR_MODE_2TO1_FRAME,

        .u32FrameRate                = 30,
        .astRegCfgs[0].pstRegs      = s_aRaw1440p4lane2f30fps10bit,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aRaw1440p4lane2f30fps10bit),

        .stDevCfg.stMcsiCfg.u32PhyFreq  = 729000000,
        .stDevCfg.stMcsiCfg.enDlanes    = VISS_LANE_NUM_4Lane,
    },
};

static int CAMERA_SetI2cInfo(VISS_DEV dev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    if (pstSnsState->stI2cInfo.fd > 0) {
        return EI_SUCCESS;
    }

    pstSnsState->stI2cInfo.u8RegBits = 16;
    pstSnsState->stI2cInfo.u8ValBits = 8;
    pstSnsState->stI2cInfo.u16I2cBusNum = 4;
    pstSnsState->stI2cInfo.u16I2cDevAddr = 0x30;
    pstSnsState->pcName = SNS_NAME;

    return EI_SUCCESS;
}
static EI_S32 CAMERA_Detect(VISS_DEV VissDev)
{
    EI_U8 u8Tmp[2];
    EI_S32 s32Ret = EI_SUCCESS;
    EI_U16 u16Id;
    SNS_STATE_S *pstSnsState = EI_NULL;
    I2C_INFO_S *pstI2cInfo = EI_NULL;

    SNS_GET_CTX(VissDev, pstSnsState);

    pstI2cInfo = &pstSnsState->stI2cInfo;

    CAMERA_CHECK_POINTER(pstI2cInfo->pfnReadReg);
    s32Ret = pstI2cInfo->pfnReadReg(pstSnsState, 0x3107, &u8Tmp[0]);
    if (s32Ret != 0) {
        PRT_VISS_ERR("%s tmp[0]=%x\n", SNS_NAME, u8Tmp[0]);
        return s32Ret;
    }
    s32Ret = pstI2cInfo->pfnReadReg(pstSnsState, 0x3108, &u8Tmp[1]);
    if (s32Ret != 0) {
        PRT_VISS_ERR("%s tmp[0]=%x,tmp[1]=%x\n", SNS_NAME, u8Tmp[0], u8Tmp[1]);
        return s32Ret;
    }
    u16Id = (u8Tmp[0] << 8) | u8Tmp[1];
    PRT_VISS_INFO("%s id: 0x%04x\n", SNS_NAME, u16Id);

    if (u16Id != 0x4210) {
        PRT_VISS_ERR("%s ID wrong! (0x%04x != 0x4210)\n", SNS_NAME, u16Id);
        return EI_FAILURE;
    }

    return EI_SUCCESS;
}

static EI_S32 CAMERA_Stream(VISS_DEV dev, EI_BOOL bOn)
{
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret = EI_SUCCESS;
    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);
    PRT_VISS_INFO("%s ----CAMERA_Stream----%d\n", SNS_NAME, bOn);

    if (bOn) {
        s32Ret = pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x0100, 0x01);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("CAMERA_Stream err*******%d\n", bOn);
        }
    } else {
        s32Ret = pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x0100, 0x00);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("CAMERA_Stream err*******%d\n", bOn);
        }
    }
    return s32Ret;

}

/* The following functions can be modified as needed */

static int CAMERA_I2cInit(VISS_DEV dev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;
    int ret = EI_SUCCESS;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    ret = CAMERA_SetI2cInfo(dev);
    CAMERA_CHECK_SUCCESS(ret);

    ret = CAMERA_I2C_Reg_Ops(&pstSnsState->stI2cInfo);
    CAMERA_CHECK_SUCCESS(ret);

    return EI_SUCCESS;
}

static int CAMERA_I2cExit(VISS_DEV dev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_PowerUp(VISS_DEV VissDev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(VissDev, pstSnsState);

    MI_VISS_SnsPower(VissDev, 0xa0000000);
    CAMERA_SensorPowerUp(VissDev, pstSnsState);

    return 0;
}

static EI_S32 CAMERA_PowerDown(VISS_DEV VissDev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(VissDev, pstSnsState);

    MI_VISS_SnsPower(VissDev, 0x00000000);

    CAMERA_SensorPowerDown(VissDev, pstSnsState);

    return 0;
}

static EI_S32 CAMERA_MirrorFlip(VISS_DEV VissDev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;
    I2C_INFO_S *pstI2cInfo = EI_NULL;
    EI_S32 s32Ret = EI_SUCCESS;
    EI_U32 u32Tmp = 0;

    SNS_GET_CTX(VissDev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    pstI2cInfo = &pstSnsState->stI2cInfo;

    PRT_VISS_INFO("%s set mirror[%d] flip[%d] \n", SNS_NAME,
        pstSnsState->u32SnsMirror, pstSnsState->u32SnsFlip);

    if (!pstSnsState->u32SnsMirror && !pstSnsState->u32SnsFlip) {
        s32Ret = pstI2cInfo->pfnWriteReg(pstSnsState, 0x3221, (u32Tmp & 0x99 ) | 0x00);
        if (s32Ret != 0) {
            PRT_VISS_ERR("%s pfnWriteReg error\n", SNS_NAME);
            return s32Ret;
        }
        return s32Ret;
    }

    /* sensor flip & mirror */
    pstI2cInfo->pfnReadReg(pstSnsState, 0x3221, &u32Tmp);
    if (s32Ret != 0) {
        PRT_VISS_ERR("%s pfnReadReg error\n", SNS_NAME);
        return s32Ret;
    }

    if (pstSnsState->u32SnsMirror) {
        s32Ret = pstI2cInfo->pfnWriteReg(pstSnsState, 0x3221, (u32Tmp & 0xf9 ) | 0x06);
    } else {
        s32Ret = pstI2cInfo->pfnWriteReg(pstSnsState, 0x3221, (u32Tmp & 0xf9 ));
    }
    if (s32Ret != 0) {
        PRT_VISS_ERR("%s pfnWriteReg error\n", SNS_NAME);
        return s32Ret;
    }

    pstI2cInfo->pfnReadReg(pstSnsState, 0x3221, &u32Tmp);
    if (s32Ret != 0) {
        PRT_VISS_ERR("%s pfnReadReg error\n", SNS_NAME);
        return s32Ret;
    }

    if (pstSnsState->u32SnsFlip) {
        s32Ret = pstI2cInfo->pfnWriteReg(pstSnsState, 0x3221, (u32Tmp & 0x9f ) | 0x60);
    } else {
        s32Ret = pstI2cInfo->pfnWriteReg(pstSnsState, 0x3221, (u32Tmp & 0x9f ));
    }
    if (s32Ret != 0) {
        PRT_VISS_ERR("%s pfnWriteReg error\n", SNS_NAME);
        return s32Ret;
    }

    return s32Ret;
}

static EI_S32 CAMERA_SetGain(ISP_DEV dev, EI_FLOAT fGain);
static EI_S32 CAMERA_SetExpTime(ISP_DEV dev, EI_FLOAT *afIntTime);

static EI_S32 CAMERA_Init(VISS_DEV dev)
{
    EI_U32 j;
    const SNS_TYPE_ATTR_S *pstSnsType;
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret;
    I2C_INFO_S *pstI2cInfo = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    pstI2cInfo = &pstSnsState->stI2cInfo;

    pstSnsType = pstSnsState->pstSnsAttr;
    for (j = 0; j < MAX_COF; j++) {
        s32Ret = pstSnsState->stI2cInfo.pfnwriteRegList(pstSnsState,
                pstSnsType->astRegCfgs[j].pstRegs, pstSnsType->astRegCfgs[j].u32RegsCnt);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("%s writeRegList err\n", SNS_NAME);
            return s32Ret;
        }
    }

    if(pstSnsType->enSnsType == SC4210_MIPI_2560_1440_25FPS_RAW12) {
        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x320e, 0x07);
        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x320f, 0x08);
        if (s32Ret != 0) {
            PRT_VISS_ERR("CAMERA_Init error\n");
            return s32Ret;
        }
    }

    if(pstSnsType->enSnsType == SC4210_MIPI_2560_1440_2TO1_25FPS_RAW10) {
        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x320e, 0x0e);
        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x320f, 0x10);
        if (s32Ret != 0) {
            PRT_VISS_ERR("CAMERA_Init error\n");
            return s32Ret;
        }
    }

    if ((pstSnsState->afIntTime[0] > 0.000001) && (pstSnsState->fGain >= 1.0)) {
        CAMERA_SetExpTime(pstSnsState->IspDev, pstSnsState->afIntTime);
        CAMERA_SetGain(pstSnsState->IspDev, pstSnsState->fGain);
    }

    CAMERA_MirrorFlip(dev);

    PRT_VISS_INFO("%s writeRegList success\n", SNS_NAME);

    return s32Ret;
}

static void CAMERA_Exit(VISS_DEV dev)
{
    CAMERA_I2cExit(dev);

    return;
}

static EI_S32 CAMERA_SetImageMode(VISS_DEV dev, SNS_TYPE_E enSnsType)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    pstSnsState->enSnsType = enSnsType;
    pstSnsState->bSyncInit = EI_FALSE;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_EnumSnstype(VISS_DEV VissDev, EI_U32 u32Index, SNS_TYPE_E *peSnstype)
{
    const SNS_TYPE_ATTR_S *pstSnsType;

    if (u32Index >= ARRAY_SIZE(s_astSnsAttr))
        return EN_ERR_NO_FOUND;

    pstSnsType = &s_astSnsAttr[u32Index];

    *peSnstype = pstSnsType->enSnsType;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_SetFrameRate(VISS_DEV VissDev, EI_FLOAT f32Fps)
{
    I2C_INFO_S *pstI2cInfo = EI_NULL;
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret = EI_SUCCESS;
    EI_U32 u32Pclk, u32Hts, u32Vts;


    SNS_GET_CTX(VissDev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    pstI2cInfo = &pstSnsState->stI2cInfo;
    u32Pclk = pstSnsState->pstSnsAttr->u32Pclk;
    u32Hts = pstSnsState->pstSnsAttr->u32Hts;

    if (pstSnsState->pstSnsAttr->enIspWdrMode == WDR_MODE_NONE) {
        if (pstSnsState->pstSnsAttr->u32FrameRate < f32Fps || 1 > f32Fps) {
            cprintf("1 <= set fps <= %d, set fps: %f\n", pstSnsState->pstSnsAttr->u32FrameRate, f32Fps);
            f32Fps = pstSnsState->pstSnsAttr->u32FrameRate;
        }

        u32Vts = u32Pclk / u32Hts / f32Fps;

        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x320e, u32Vts >> 8);
        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x320f, u32Vts);

        if (s32Ret != 0) {
            cprintf("CAMERA_Init error\n");
            return s32Ret;
        }
    } else if (pstSnsState->pstSnsAttr->enIspWdrMode == WDR_MODE_2TO1_FRAME) {
        if (pstSnsState->pstSnsAttr->u32FrameRate < f32Fps || 1 > f32Fps) {
            cprintf("1 <= set fps <= %d, set fps: %f\n", pstSnsState->pstSnsAttr->u32FrameRate, f32Fps);
            f32Fps = pstSnsState->pstSnsAttr->u32FrameRate;
        }

        u32Vts = u32Pclk / u32Hts / f32Fps;

        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x320e, u32Vts >> 8);
        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x320f, u32Vts);

        if (s32Ret != 0) {
            cprintf("CAMERA_Init error\n");
            return s32Ret;
        }
    } else {
        return EN_ERR_NOT_SUPPORT;
    }
    pstSnsState->pstSnsAttr->u32Vts = u32Vts;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_InitSensorExpFunction(SENSOR_EXP_FUNC_S *pstSensorExpFunc)
{
    CAMERA_CHECK_POINTER(pstSensorExpFunc);

    memset(pstSensorExpFunc, 0, sizeof(SENSOR_EXP_FUNC_S));

    pstSensorExpFunc->pfnSensorPowerUp  = CAMERA_PowerUp;
    pstSensorExpFunc->pfnSensorPowerDown = CAMERA_PowerDown;
    pstSensorExpFunc->pfnSensorDetect   = CAMERA_Detect;
    pstSensorExpFunc->pfnSensorInit     = CAMERA_Init;
    pstSensorExpFunc->pfnSensorStream   = CAMERA_Stream;
    pstSensorExpFunc->pfnSensorExit     = CAMERA_Exit;
    pstSensorExpFunc->pfnSensorSetImageMode   = CAMERA_SetImageMode;
    pstSensorExpFunc->pfnSensorEnumSnstype   = CAMERA_EnumSnstype;
    pstSensorExpFunc->pfnSensorSetFrameRate   = CAMERA_SetFrameRate;
    pstSensorExpFunc->pfnSensorSetMirrorFlip = CAMERA_MirrorFlip;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_GetAeDefault(ISP_DEV dev, AE_SENSOR_DEFAULT_S *pstAeSnsDft)
{
    CAMERA_CHECK_POINTER(pstAeSnsDft);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_SetFps(ISP_DEV dev, EI_FLOAT f32Fps, AE_SENSOR_DEFAULT_S *pstAeSnsDft)
{
    VISS_DEV Dev;

    SNS_GET_ISP_TO_VISS(dev, Dev);

    CAMERA_CHECK_POINTER(pstAeSnsDft);

    return CAMERA_SetFrameRate(Dev, f32Fps);
}

static EI_S32 CAMERA_SetExpTime(ISP_DEV dev, EI_FLOAT *afIntTime)
{
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret = EI_SUCCESS;
    EI_U32 u32Pclk, u32Hts, u32Vts;
    EI_U32 shutter_time;
    EI_U32 lexp, mexp;
    VISS_DEV Dev;

    SNS_GET_ISP_TO_VISS(dev, Dev);

    SNS_GET_CTX(Dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);
    CAMERA_CHECK_POINTER(afIntTime);
    pstSnsState->afIntTime[0] = afIntTime[0];
    pstSnsState->afIntTime[1] = afIntTime[1];
    pstSnsState->afIntTime[2] = afIntTime[2];
    pstSnsState->afIntTime[3] = afIntTime[3];
    pstSnsState->IspDev = dev;
    CAMERA_CHECK_POWERON(pstSnsState);

    u32Pclk = pstSnsState->pstSnsAttr->u32Pclk;
    u32Hts = pstSnsState->pstSnsAttr->u32Hts;
    u32Vts = pstSnsState->pstSnsAttr->u32Vts;

    if ((u32Pclk == 0) || (u32Hts == 0) || (u32Vts == 0)) {
        PRT_VISS_ERR("error! u32Pclk %d, u32Hts %d, u32Vts %d\n", u32Pclk, u32Hts, u32Vts);
        return EI_FAILURE;
    }

    /* afIntTime[0] long/medium/short/vshort exptime (s) */
    shutter_time = 2 * afIntTime[0] * u32Pclk / u32Hts;
    if (shutter_time < 4)
        shutter_time = 4;

    //printf("exp_time: %d, %f(s)!\n", shutter_time, afIntTime[0]);

    if (pstSnsState->pstSnsAttr->enIspWdrMode == WDR_MODE_NONE) {
        if (shutter_time > (2 * (u32Vts - 2)))
            shutter_time = 2 * (u32Vts - 2);

        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e00, (shutter_time >> 12) & 0x0f);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e01, (shutter_time >> 4) & 0xff);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e02, (shutter_time << 4) & 0xf0);

        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("\n");
        }
    } else if (pstSnsState->pstSnsAttr->enIspWdrMode == WDR_MODE_2TO1_FRAME) {
        if (afIntTime[1] < 1)
            afIntTime[1] = 8;

        if (shutter_time > 2 * (u32Vts - MAX_SHORT_EXP -3))
            lexp = 2 * (u32Vts - MAX_SHORT_EXP -3);
        else
            lexp = shutter_time;

        mexp = shutter_time / afIntTime[1];

        if (mexp < 4)
            mexp = 4;
        if (mexp > 2 * (MAX_SHORT_EXP - 1))
            mexp = 2 * (MAX_SHORT_EXP - 1);

        lexp = mexp * afIntTime[1];

        //printf("exp_time: %d, %d\n", lexp, mexp);

        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e00, (lexp >> 12) & 0x0f);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e01, (lexp >> 4) & 0xff);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e02, (lexp << 4) & 0xf0);

        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e04, (mexp >> 4) & 0xff);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e05, (mexp << 4) & 0xf0);

        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("\n");
        }

        shutter_time = lexp;
    }

    afIntTime[0] = (EI_FLOAT)(shutter_time / 2) * u32Hts / u32Pclk;
    if (afIntTime[0] < 0.00001) {
        PRT_VISS_WARN("Warning! afIntTime[0] < 0.00001, now force 0.00001 \n");
        afIntTime[0] = 0.00001;
    }

    return s32Ret;
}

static EI_S32 CAMERA_SetGain(ISP_DEV dev, EI_FLOAT fGain)
{
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret = EI_SUCCESS;
    EI_U8 aFineGain=0x40,aGain=0x03,dFineGain=0x80,dGain=0x00;
    EI_U8 aCoarseGain = 0;
    EI_U8 dCoarseGain = 0;
    EI_U32 u32Again, u32Dgain;

    VISS_DEV Dev;

    SNS_GET_ISP_TO_VISS(dev, Dev);

    SNS_GET_CTX(Dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);
    pstSnsState->fGain = fGain;
    CAMERA_CHECK_POWERON(pstSnsState);

    if (fGain < 1)
        fGain = 1;

    if (fGain <= 43.656) {
        u32Again = fGain * 64;
        u32Dgain = 128;
    } else if (fGain <= 31.5 * 43.656) {
        u32Again = 43.656 * 64;
        u32Dgain = fGain / 43.656 * 128;
    } else {
        u32Again = 43.656 * 64;
        u32Dgain = 31.5 * 128;
    }

    if(u32Again < 176)
    {
        for(aCoarseGain = 1; aCoarseGain <= 2; aCoarseGain = aCoarseGain * 2)
        {
            if(u32Again < (64 * 2 * aCoarseGain))
            {
                break;
            }
        }

        aFineGain = u32Again / aCoarseGain;
    }
    else
    {
        for(aCoarseGain = 1; aCoarseGain <= 8; aCoarseGain = aCoarseGain * 2)
        {
            if(u32Again < (64 * 2 * aCoarseGain * 2.75))
            {
                break;
            }
        }
        aFineGain = 1.0*u32Again / aCoarseGain / 2.75;
    }

    for ( ; aCoarseGain >= 2; aCoarseGain=aCoarseGain/2)
    {
        aGain = (aGain << 1) | 0x01;
    }

    aGain = (u32Again >= 176) ? (aGain | 0x20) : (aGain & 0x1f);

    for(dCoarseGain = 1; dCoarseGain <= 16; dCoarseGain = dCoarseGain * 2)
    {
        if(u32Dgain < (128 * 2 * dCoarseGain))
        {
            break;
        }
    }
    dFineGain = u32Dgain / dCoarseGain;

    for ( ; dCoarseGain >= 2; dCoarseGain=dCoarseGain/2)
    {
        dGain = (dGain << 1) | 0x01;
    }

    s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e07, dFineGain);
    s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e06, dGain);
    s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e09, aFineGain);
    s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e08, aGain);

    if (pstSnsState->pstSnsAttr->enIspWdrMode == WDR_MODE_2TO1_FRAME) {
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e13, aFineGain);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e12, aGain);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e11, dFineGain);
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3e10, dGain);
    }

    if (s32Ret != EI_SUCCESS) {
        PRT_VISS_ERR("\n");
    }

    return s32Ret;
}

static EI_S32 CAMERA_InitAeExpFunction(AE_SENSOR_EXP_FUNC_S *pstExpFuncs)
{
    CAMERA_CHECK_POINTER(pstExpFuncs);

    memset(pstExpFuncs, 0, sizeof(AE_SENSOR_EXP_FUNC_S));

    pstExpFuncs->pfnGetAeDefault    = CAMERA_GetAeDefault;
    pstExpFuncs->pfnSetFps          = CAMERA_SetFps;
    pstExpFuncs->pfnSetExpTime      = CAMERA_SetExpTime;
    pstExpFuncs->pfnSetGain         = CAMERA_SetGain;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_GetAwbDefault(ISP_DEV dev, AWB_SENSOR_DEFAULT_S *pstAwbSnsDft)
{
    CAMERA_CHECK_POINTER(pstAwbSnsDft);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_InitAwbExpFunction(AWB_SENSOR_EXP_FUNC_S *pstExpFuncs)
{
    CAMERA_CHECK_POINTER(pstExpFuncs);

    memset(pstExpFuncs, 0, sizeof(AWB_SENSOR_EXP_FUNC_S));
    pstExpFuncs->pfnGetAwbDefault = CAMERA_GetAwbDefault;

    return EI_SUCCESS;
}

/****************************************************************************
 * callback structure                                                       *
 ****************************************************************************/

static EI_S32 CAMERA_CtxInit(VISS_DEV dev)
{
    SNS_STATE_S *pastSnsStateCtx = EI_NULL;

    SNS_GET_CTX(dev, pastSnsStateCtx);

    CAMERA_CHECK_POINTER(pastSnsStateCtx);

    memset(pastSnsStateCtx, 0, sizeof(SNS_STATE_S));

    pastSnsStateCtx->pstPowerUpAct      = s_stPowerUpAct;
    pastSnsStateCtx->pstPowerDownAct    = s_sPowerDownAct;
    pastSnsStateCtx->u8PwrUpActs        = ARRAY_SIZE(s_stPowerUpAct);
    pastSnsStateCtx->u8PwrDnActs        = ARRAY_SIZE(s_sPowerDownAct);

    return EI_SUCCESS;
}

static EI_VOID CAMERA_CtxExit(VISS_DEV dev)
{
    return ;
}

static EI_S32 CAMERA_RegisterVissCallback(VISS_DEV dev, SNS_TYPE_E enType)
{
    EI_S32 s32Ret;
    SENSOR_S stSns = {0};
    EI_U32 i;
    SNS_STATE_S *pstSnsState = EI_NULL;

    s32Ret = CAMERA_CtxInit(dev);
    if (EI_SUCCESS != s32Ret) {
        return EI_FAILURE;
    }

    SNS_GET_CTX(dev, pstSnsState);

    for (i = 0; i < ARRAY_SIZE(s_astSnsAttr); i++) {
        if (enType == s_astSnsAttr[i].enSnsType) {
            pstSnsState->pstSnsAttr = &s_astSnsAttr[i];
            break;
        }
    }

    pstSnsState->enSnsType = enType;
    pstSnsState->Dev = dev;

    if (i >= ARRAY_SIZE(s_astSnsAttr)) {
        PRT_VISS_ERR("%s does not support this chn configuration", SNS_NAME);
        return EI_FAILURE;
    }

    s32Ret = CAMERA_I2cInit(dev);
    if (EI_SUCCESS != s32Ret) {
        return EI_FAILURE;
    }

    stSns.stSnsAttrInfo.eSensorId = SNS_ID;
    stSns.stSnsAttrInfo.enDevType = DEV_TYPE;
    stSns.stSnsAttrInfo.pstSns = pstSnsState;

    s32Ret  = CAMERA_InitSensorExpFunction(&stSns.stSnsAttrInfo.stSnsExp);
    s32Ret |= VISS_SensorRegCallBack(dev, &stSns);
    if (EI_SUCCESS != s32Ret) {
        PRT_VISS_ERR("%s sensor register callback function failed!\n", SNS_NAME);
        return s32Ret;
    }

    s32Ret = CAMERA_OpenI2c(pstSnsState);
    CAMERA_CHECK_SUCCESS(s32Ret);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_UnregisterVissCallback(VISS_DEV dev)
{
    EI_S32 s32Ret;
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);

    s32Ret = CAMERA_ExitI2c(pstSnsState);
    CAMERA_CHECK_SUCCESS(s32Ret);

    s32Ret = VISS_SensorUnRegCallBack(dev, SNS_ID);
    if (EI_SUCCESS != s32Ret) {
        PRT_VISS_ERR("%s sensor unregister callback function failed!\n", SNS_NAME);
        return s32Ret;
    }

    CAMERA_CtxExit(dev);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_RegisterIspCallback(VISS_DEV Dev, ISP_DEV dev, ISP_3ALIB_S *pstAeLib, ISP_3ALIB_S *pstAwbLib)
{
    EI_S32 s32Ret;
    AE_SENSOR_REGISTER_S  stAeRegister;
    AWB_SENSOR_REGISTER_S stAwbRegister;

    CAMERA_CHECK_POINTER(pstAeLib);
    CAMERA_CHECK_POINTER(pstAwbLib);

    SNS_SET_ISP_TO_VISS(dev, Dev);

    stAeRegister.SnsId = SNS_ID;
    stAwbRegister.SnsId = SNS_ID;

    s32Ret  = CAMERA_InitAeExpFunction(&stAeRegister.stSnsExp);
    s32Ret |= EI_MI_AE_SensorRegCallBack(dev, pstAeLib, &stAeRegister);

    if (EI_SUCCESS != s32Ret) {
        EI_TRACE_ISP(EI_DBG_ERR, "%s register callback function to ae lib failed!\n", SNS_NAME);
        return s32Ret;
    }

    s32Ret  = CAMERA_InitAwbExpFunction(&stAwbRegister.stSnsExp);
    s32Ret |= EI_MI_AWB_SensorRegCallBack(dev, pstAwbLib, &stAwbRegister);

    if (EI_SUCCESS != s32Ret) {
        EI_TRACE_ISP(EI_DBG_ERR, "%s register callback function to awb lib failed!\n", SNS_NAME);
        return s32Ret;
    }

    return EI_SUCCESS;
}

static EI_S32 CAMERA_UnregisterIspCallback(ISP_DEV dev, ISP_3ALIB_S *pstAeLib, ISP_3ALIB_S *pstAwbLib)
{
    EI_S32 s32Ret;

    CAMERA_CHECK_POINTER(pstAeLib);
    CAMERA_CHECK_POINTER(pstAwbLib);

    s32Ret = EI_MI_AE_SensorUnRegCallBack(dev, pstAeLib, SNS_ID);
    if (EI_SUCCESS != s32Ret) {
        EI_TRACE_ISP(EI_DBG_ERR, "%s unregister callback function to ae lib failed!\n", SNS_NAME);
        return s32Ret;
    }

    s32Ret = EI_MI_AWB_SensorUnRegCallBack(dev, pstAwbLib, SNS_ID);
    if (EI_SUCCESS != s32Ret) {
        EI_TRACE_ISP(EI_DBG_ERR, "%s unregister callback function to awb lib failed!\n", SNS_NAME);
        return s32Ret;
    }

    return EI_SUCCESS;
}

static EI_S32 CAMERA_GetVissDevAttrBySns(SNS_TYPE_E enType,
    VISS_DEV_ATTR_S *pstVissDevAttr)
{
    EI_U32 i;
    const SNS_TYPE_ATTR_S *pstSnsType;

    for (i = 0; i < ARRAY_SIZE(s_astSnsAttr); i++) {
        if (enType == s_astSnsAttr[i].enSnsType) {
            pstSnsType = &s_astSnsAttr[i];
            pstVissDevAttr->stSize          = pstSnsType->stSize;
            pstVissDevAttr->enWorkMode      = pstSnsType->enWorkMode;
            pstVissDevAttr->mClock          = pstSnsType->u32Mclock;
            pstVissDevAttr->enPixelFormat   = pstSnsType->enPixelFormat;
            pstVissDevAttr->enWdrMode       = pstSnsType->enWdrMode;
            pstVissDevAttr->enIspWdrMode    = pstSnsType->enIspWdrMode;
            pstVissDevAttr->enRgbSeq        = pstSnsType->enRgbSeq;
            pstVissDevAttr->u32ModuleClk    = pstSnsType->u32ModuleClk;
            pstVissDevAttr->u32Fps          = pstSnsType->u32FrameRate;
            pstVissDevAttr->u32IspClk       = pstSnsType->u32IspClk;
            pstVissDevAttr->u32IppuClk      = pstSnsType->u32IppuClk;
            pstVissDevAttr->pcSnsName       = SNS_NAME;
            pstVissDevAttr->stDevCfg        = pstSnsType->stDevCfg;
            return EI_SUCCESS;
        }
    }

    PRT_VISS_ERR("%s does not support this dev configuration", SNS_NAME);

    return EI_FAILURE;
}

static EI_S32 CAMERA_GetVissChnAttrBySns(SNS_TYPE_E enType,
    VISS_CHN_ATTR_S *pstVissChnAttr)
{
    EI_U32 i;
    const SNS_TYPE_ATTR_S *pstSnsType;

    for (i = 0; i < ARRAY_SIZE(s_astSnsAttr); i++) {
        if (enType == s_astSnsAttr[i].enSnsType) {
            pstSnsType = &s_astSnsAttr[i];
            pstVissChnAttr->stSize          = pstSnsType->stSize;
            pstVissChnAttr->enPixelFormat   = pstSnsType->enPixelFormat;
            pstVissChnAttr->stFrameRate.s32SrcFrameRate     = pstSnsType->u32FrameRate;
            return EI_SUCCESS;
        }
    }

    PRT_VISS_ERR("%s does not support this chn configuration", SNS_NAME);

    return EI_FAILURE;

}

CAMERA_OBJ_S stCameraSc4210mipiObj = {
    .pfnRegisterVissCallback    = CAMERA_RegisterVissCallback,
    .pfnUnRegisterVissCallback  = CAMERA_UnregisterVissCallback,
    .pfnRegisterIspCallback     = CAMERA_RegisterIspCallback,
    .pfnUnRegisterIspCallback   = CAMERA_UnregisterIspCallback,
    .pfnGetVissDevAttrBySns     = CAMERA_GetVissDevAttrBySns,
    .pfnGetVissChnAttrBySns     = CAMERA_GetVissChnAttrBySns,
};

#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */

